// @(#)main.cc
// Time-stamp: <2009-02-26 00:48:57 root>
// Copyright 2008 Julian Qian
// Author: root@localhost.localdomain
// Version: $Id: main.c,v 0.0 2008/10/04 01:15:44 root Exp $
// Keywords: 
///

#include <stdlib.h>
#include <getopt.h>
// #include <stdarg.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <iostream>

#include <boost/thread/thread.hpp>

#include "main.hh"
// #include "dispatch.hh"
#include "server.hh"
#include "log.hh"
#include "thread.hh"
#include "alarm.hh"
#include "heart.hh"
#include "ctrl.hh"
#include "signal.hh"
#include "excep.hh"
#include "soap/wrapesms.hh"


int main(int argc, char *argv[]) {
    using namespace boost::interprocess;
    
	// Become a deamon
	int c, helpflg = 0;
	struct option longopts[] = {
		{"add", 1, 0, 'a'},
        {"check", 1, 0, 'c'},
        {"clear", 1, 0, 'e'},        
		{"daemon", 1, 0, 'd'},
		{"help", 1, 0, 'h'},
        {"list", 1, 0, 'l'},
		{"msg", 1, 0, 'm'},
		{"print_msg", 1, 0, 'p'},        
        {"quit", 1, 0, 'q'},
		{0,0,0,0}
	};
	while((c = getopt_long(argc, argv, "a:c:dehlm:pq", longopts, NULL)) != EOF){
		switch(c){
        case 'a':
            // defense control
            LInfo("Push alarm from cmd: " << optarg);
            Ctrl::push_alarm(optarg);
            exit(0);
        case 'c':
            LInfo("Check devid whether on-line: " << optarg);
            stat_t stat;
            stat = Heart::check_proto(atoi(optarg));
            std::cout << stat << std::endl;
            exit(0);
		case 'd':
            LInfo("Run as a daemon server.");
			daemon_init();
			// daemon_init("/dev/log", LOG_DAEMON);
            break;
        case 'e':
            LInfo("Clear shared memory");
            clean_memory_sgement();
            exit(0);
		case 'h':
            std::cout << "Usage: ehomed -d" << std::endl;
            exit(0);
        case 'l':
            Heart::print_protos();
            exit(0);
        case 'm':
            // send msg
            LInfo("One msg is sent: " << optarg);
            Wrapesms::push_msg(optarg);
            exit(0);
        case 'p':
            LInfo("Print msg queue:");
            Wrapesms::print_msglist();
            exit(0);
        case 'q':
            LInfo("End Servo now...");
            push_sig(get_pid(), 0);
            // quit servo
            exit(0);
		default:
            std::cout << "Usage: ehomed -d" << std::endl;
            exit(0);            
		}
	}

    // Eh0m3 sails off~~~
    LInfo("################Eh0m3 sails off################");

    set_pid();
    sig_setup();
    
    // exit(0);
	// Signal(SIGCHLD, sig_chld);
	// signal(SIGINT, exit);

    // 1) Alarm
    // 2) Heart
    // 3) Server

    shared_memory_object::remove(SHM_HEART_SEG);
    shared_memory_object::remove(SHM_MSG_SEG);
    
    try{
        managed_shared_memory segment
            // create     //segment name   //segment size in bytes
            // (create_only, SHM_HEART_SEG,       655360);
            (open_or_create, SHM_HEART_SEG,       655360);


        //Initialize the shared memory STL-compatible allocator
        HPShmemAllocator alloc_inst (segment.get_segment_manager());

        //Construct a shared memory map.
        //Note that the first parameter is the comparison function,
        //and the second one the allocator.
        //This the same signature as std::map's constructor taking an allocator
        HeartMap* hmap = segment.construct<HeartMap>(SHM_HEART_OBJ) (std::less<devid_t>(), alloc_inst);

        try{
            managed_shared_memory segment_msg(open_or_create, SHM_MSG_SEG, 65536);
            MSGShmemAllocator alloc_inst_msg(segment_msg.get_segment_manager());
            MsgList* pmlist = segment_msg.construct<MsgList>(SHM_PUTMSG_OBJ)(alloc_inst_msg);
            // MsgList* gmlist = segment_msg.construct<MsgList>(SHM_GETMSG_OBJ)(alloc_inst_msg);

            // ATTATION: call order
            Wrapesms::initWrapesms(pmlist);
            usleep(100);

            Heart::initHeart(hmap);
            usleep(100);

            Alarm::theAlarm();
            usleep(100);

            //Insert data in the map
            // for(int i = 0; i < 100; ++i){
            //    mymap->insert(HPPair(i, (float)i));
            // }

            LDebug("Dispatch threads.");
            
            Thread thd[5];

            thd[0].run((Functype)PServer, NULL);
            thd[1].run((Functype)PHeart, NULL);    
            thd[2].run((Functype)PAlarm, NULL);
            thd[3].run((Functype)PCleanStatus, NULL);
            thd[4].run((Functype)PCtrl, NULL);

            thd[0].join();
            thd[1].join();
            thd[2].join();
            thd[3].join();
            thd[4].join();            

            // for(int i=0; i<5; i++){
            //     thd[i].join();
            // }
            /*
              boost::thread th_server(&PServer);
              boost::thread th_heart(&PHeart);
              boost::thread th_alarm(&PAlarm);
              boost::thread th_clean(&PCleanStatus);
              boost::thread th_ctrl(&PCtrl);

              th_server.join();
              th_heart.join();
              th_alarm.join();
              th_clean.join();
              th_ctrl.join();
            */
        }
        catch(const interprocess_exception &ex){
            shared_memory_object::remove(SHM_MSG_SEG);
            throw Exception(ex.what());
        }            
        
    }
    catch(const interprocess_exception &ex){
        shared_memory_object::remove(SHM_HEART_SEG);
        throw Exception(ex.what());
    }    
    
    LDebug("Dispatch End <-- should not run here.");
	exit(0);
}

void daemon_init(){
	int		i;
	pid_t	pid;

	if ( (pid = fork()) != 0)
		exit(0);			// parent terminates

	// 41st child continues
	setsid();				// become session leader

	signal(SIGHUP, SIG_IGN);
	if ( (pid = fork()) != 0)
		exit(0);			// 1st child terminates

	chdir("/");				// change working directory 

	umask(0);				// clear our file mode creation mask 

	// for (i = 0; i < MAXFD; i++)
	// 	close(i);

    LInfo( "Current work directory: "<< get_current_dir_name() );
}

void daemon_exit(){
    
}

////////////////////////////////////////////////////////////////
///////////////// Some Threads Beging //////////////////////////
////////////////////////////////////////////////////////////////

void PServer(){
    LDebug("Begin servo...");
    Server ser;
    ser.servo();
}

void PAlarm(){
    LDebug("Begin Alarm runloop");
    ALARM_runloop(8);
}

void PHeart(){
    LDebug("Begin Heart runloop");
    HEART_runloop(60);
}

void PCleanStatus(){
    try{
        Heart* ht = Heart::theHeart();
        while(1){
            ht->clean_heart();
            sleep(120);
        }
    }
    catch(...){
        LFatal("PCleanStatus Failed!");
    }
}

void PCtrl(){
    LDebug("Begin msg_servo...");
    try{
        Ctrl ctl;
        ctl.msg_servo();
    }
    catch(...){
        LFatal("PCtrl failed!");
    }
}


////////////////////////////////////////////////////////////////
// Dispatch Functions
////////////////////////////////////////////////////////////////
#ifdef DISPATCH_FUNCTION_

void ALARM_runloop(int delay = 5){
    LInfo("Alarm dispatch");
    while(1){
        _DISPATCH_send_dev_alarm();
        sleep(5);
        _DISPATCH_send_phone_alarm();
        sleep(delay);
    }
}

void _DISPATCH_send_phone_alarm(){
    try{
        Alarm* ala = Alarm::theAlarm();
        ala->send_phone_alarm();
    }
    catch(...){
        
    }
}

void _DISPATCH_send_dev_alarm(){
    try{
        Alarm* ala = Alarm::theAlarm();
        ala->send_dev_alarm();
    }
    catch(...){
        
    }
}

void HEART_runloop(int delay = 60){
    // Dispatch* ds = Dispatch::theDispatch();
    // ds->engine(_HEART_dispatcher, delay); // every 1 min
    while(1){
        sleep(delay);
        _DISPATCH_active_heart();
    }
}

void _DISPATCH_active_heart(){
    try{
        Heart* hea = Heart::theHeart();
        hea->active_heart();
    }
    catch(...){
        LInfo("_DISPATCH_active_heart failed!");
    }
}

#endif
